#bad code
#but done now 230917
#edited 23-12-18 fine
#240607 更改了目录，需要修改，需要建一个存放图片的目录image
#using tensorflow-1.9.0 opencv-3.4.2
import time

import tensorflow as tf
from random import randint
import cv2
import numpy as np
import matplotlib.pyplot as plt

#导入数据集
from tensorflow.examples.tutorials.mnist import input_data
from PIL import Image
#mnist=input_data.read_data_sets("/temp_zuoti/data/",one_hot="True") #由于移动了目录
mnist=input_data.read_data_sets("/MNIST_data/",one_hot="True")
def image_inverse(x):#反色变换函数
    value_max = np.max(x)
    y = value_max - x
    return y

#灰度变换函数
def imagehuidutransplant(i):
    # 打开图片
    gray_img = np.asarray(cv2.imread('C:/Users/Admin/Desktop/image/predicted/image-predicted-{}.png'.format(i), 0))#Image.open(r'C:/Users/Admin/Desktop/image/image-predicted.png').convert('L'



    plt.imshow(gray_img, cmap='gray', vmin=0, vmax=255)
    plt.savefig('C:/Users/Admin/Desktop/image/imagehuidu-{}.png'.format(i))  # 保存图片
    plt.show()
    plt.pause(0.3)

    inv_img = image_inverse(gray_img)  # 将原图形作为矩阵传入函数中，进行反色变换
    plt.imshow(inv_img, cmap='gray', vmin=0, vmax=255)
    plt.savefig('C:/Users/Admin/Desktop/image/imagehuidu-{}.png'.format(i))  # 保存图片
    plt.show()
    plt.pause(0.3)

#Canny算法进行边缘检测
def showimagecut(i):
    img = cv2.imread('C:/Users/Admin/Desktop/image/predicted/image-predicted-{}.png'.format(i), 0)

    #直接调用函数
    dst = cv2.Canny(img, 100, 200)  # Canny 边缘检测

    cv2.imshow("img", np.hstack((img, dst)))  # 显示图片
    cv2.imwrite('C:/Users/Admin/Desktop/image/predicted/image-fenge-{}.jpg'.format(i), np.hstack((img, dst)))  # 保存图片
    cv2.waitKey(10)
    plt.pause(1)
    cv2.destroyAllWindows()
    """
    Canny 是基于一阶微分的
    首先用高斯滤波平滑图像。
    计算梯度幅值图像和方向角度图像
    对梯度图像应用非极大值抑制(根据第二步求出的角度图像，用该像素点 比较 在梯度方向和其反方向的像素点。如果该像素点的梯度幅值最大则保留；否则，删去。)
    使用双阈值处理和连通性分析来检测连接边缘  (根据设置的两个阈值（ 为低阈值  为高阈值），就会将幅值图像划为三部分，进行如下的分割
    像素点的响应强度是 > TH 的，那么认为是真正的边缘
    像素点的响应强度是 < TL的，那么认为是伪边缘，删去
    如果介于两者之间，则检查周围的8领域，如果存在真正的边缘就保留，为了连接边缘。否则就删去)
    """

#显示部分图片
def show_image():
    train_data=mnist.train.images
    test_data=mnist.test.images
    plt.figure()
    x=0
    for i in range(6,19,1):
        x=x+1
        im=train_data[i].reshape(28,28)
        plt.imshow(im)
        plt.savefig('C:/Users/Admin/Desktop/image/image-{}.png'.format(x + 1))
        plt.pause(0.5)


logs_path='log_mnist_softmax'#模型日志保存路径
batch_size=100
learning_rate=0.01#学习率
training_epochs=10#训练回合

#这个原书里的，用不上，这是作者自己写的调用代码
#mnist=mnist_data.read_data_sets("data")

#定义变量以及数据类型（张量形式）
X=tf.placeholder(tf.float32,[None,28,28,1],name='input')#输入若干图片 输入任意数量，28*28 一份
Y_=tf.placeholder(tf.float32,[None,10])#预测结果最终输出结果1*10的矩阵，即0-9对应的标签，如[0,1,0,0,0,0,0,0,0,0]表示1
W=tf.Variable(tf.zeros([784,10]))#
b=tf.Variable(tf.zeros([10]))#
XX=tf.reshape(X,[-1,784]) #将X张量自动转成1*784的行矩阵

Y=tf.nn.softmax(tf.matmul(XX,W)+b,name='output')#softmax函数激活函数
cross_entropy=-tf.reduce_mean(Y_*tf.log(Y)*1000.0)#交叉熵
correct_prediction=tf.equal(tf.argmax(Y,1),tf.argmax(Y_,1))

accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

train_step=tf.train.GradientDescentOptimizer(0.005).minimize((cross_entropy))#梯度下降法，求解交叉熵最小值

tf.summary.scalar("cost",cross_entropy)#损失率
tf.summary.scalar("accuracy",accuracy)#精确度
summary_op=tf.summary.merge_all()

#开始训练
with tf.Session() as sess:
    print("------start------")
    sess.run(tf.global_variables_initializer())

    #定义计算图
    writer=tf.summary.FileWriter(logs_path,graph=tf.get_default_graph())
    startime=time.time()
    for epoch in range(training_epochs):
        batch_count=int(50000/batch_size)#mnist.train.num_example
        for i in range(batch_count):
            #读取训练集数据
            batch_x,batch_y=mnist.train.next_batch(batch_size)
            batch_x=batch_x.reshape(100,28,28,1)#28*28,100份，但是在一个列表
            sess.run(train_step,feed_dict={X:batch_x,Y_:batch_y})
        print("\neponch: ",epoch)

        images_x=mnist.test.images.reshape(10000,28,28,1)#四维张量，10000张图片，一张图片为28*28
        #测试结果输出，精确度
        print("accuracy: ",accuracy.eval \
        (feed_dict={X:images_x,Y_:mnist.test.labels}))

        print("cost: ",cross_entropy.eval\
            (feed_dict={X:images_x,Y_:mnist.test.labels}))

    endtime=time.time()
    print("-------done------")
    print("using {} second".format(endtime-startime))

    print("show some figures?[Y/N]")
    tem=input()
    if tem=='Y':
        #展示几张部分数据集的图片
        show_image()
    else :
        print("Next")

    #进行预测，随机选择一张图片预测
    for i in range(5):
        print("the NO.{} Predicted result is :".format(i+1))
        #模型预测，随机选择一张图片
        num=randint(0,mnist.test.images.shape[0])
        img=mnist.test.images[num]#选择的图片
        img_x=img.reshape(28,28,1)#用于预测，以28*28*1的张量形式
        img_y=img.reshape(28,28)#用于plt显示图片 28*28的图片
        plt.imshow(img_y)#图片展示
        plt.savefig('C:/Users/Admin/Desktop/image/predicted/image-predicted-{}.png'.format(i+1))#图片保存
        plt.pause(1)

        #用于预测及保存模型
        classification= sess.run(tf.argmax(Y,1),feed_dict={X:[img_x]})#预测结果返回
        print("neual network predicted is")
        print(classification[0])#输出预测结果
        #print(classification)
        print("real label is :")
        print(np.argmax(mnist.test.labels[num]))#输出实际的标签
        if classification[0]==np.argmax(mnist.test.labels[num]):
            print("Predicted successfully\n")
        else:
            print("Predicted failed\n")
        saver=tf.train.Saver()

        # 进行灰度变换，反色变换
        imagehuidutransplant(i+1)

        # 显示图像分割结果，进行边缘检测
        showimagecut(i+1)

    # 模型保存
    save_path=saver.save(sess,'./savemodel/ckpt_file')
    print("model saved to %s"%save_path)



